﻿using System.IO.Compression;
using System.Xml.Linq;

namespace MySoftLab.DapFlashCore.Targets.Packs
{
    public class PackExtracter
    {
        public PackExtracter()
        {

        }

        private static uint ParseHexString(string hexStr)
        {
            hexStr = hexStr.ToLower().Trim().Replace("0x", "");
            return Convert.ToUInt32(hexStr, 16);
        }

        private static MemoryRegion[] FillMemoryRegion(XElement parent)
        {
            // 提取memory元素
            var memories = parent.Elements("memory").ToArray();

            List<MemoryRegion> result = new List<MemoryRegion>();

            foreach (var memory in memories)
            {
                // 首先提取name
                var nameAttribute = memory.Attribute("name");
                if (null == nameAttribute)
                {
                    nameAttribute = memory.Attribute("id");
                }

                if (null == nameAttribute)
                {
                    return [];
                }

                string name = nameAttribute.Value.ToLower();
                if (name.Contains("flash") || name.Contains("rom"))
                {
                    // flash
                    uint start = ParseHexString(memory.Attribute("start").Value);
                    uint length = ParseHexString(memory.Attribute("size").Value);
                    bool isBootMemory = memory.Attribute("startup").Value == "1";

                    result.Add(new FlashRegion(name, start, length, 0, 0, isBootMemory, null));
                }
                else if (name.Contains("ram"))
                {
                    // ram
                    uint start = ParseHexString(memory.Attribute("start").Value);
                    uint length = ParseHexString(memory.Attribute("size").Value);
                    result.Add(new RamRegion(name, start, length));
                }
            }

            return [.. result];
        }

        public static CommonTarget? ExtractTarget(string packPath, string queryTargetName)
        {
            string targetName = "";
            MemoryMap memoryMap = new MemoryMap();
            FlashAlgo? flashAlgo;

            // 首先解压索引文件并解析
            using var archive = ZipFile.OpenRead(packPath);

            foreach (var entry in archive.Entries)
            {
                if (entry.Name.Contains(".pdsc"))
                {
                    // 解压缩
                    using var pdscStream = entry.Open();

                    var xdoc = XDocument.Load(pdscStream);
                    var devices = xdoc.Descendants("device").Where(x => x.Attribute("Dname").Value.ToUpper().Contains(queryTargetName.ToUpper())).ToArray();

                    if (devices.Length > 0)
                    {
                        var device = devices.First();

                        // 如果device中存在RAM定义，则优先从device节点提取RAM定义，否则从父节点DsubFamily提取
                        var regions = FillMemoryRegion(device);
                        memoryMap.Regions.AddRange(regions);

                        // 如果没有ram区域，则从父节点查找
                        if (!regions.Any(x => x.MemoryType == MemoryType.RAM))
                        {
                            var subFamily = device.Parent;
                            regions = FillMemoryRegion(subFamily);
                            memoryMap.Regions.AddRange(regions);
                        }

                        targetName = device.Attribute("Dname").Value;

                        // 提取flash算法
                        var algoEle = device.Elements("algorithm").Where(x => x.Attribute("default").Value == "1").FirstOrDefault();
                        if (null == algoEle)
                        {
                            return null;
                        }
                        string flmPath = algoEle.Attribute("name").Value;
                        var flmName = Path.GetFileName(flmPath);
                        var flmEntry = archive.Entries.Where(x => x.Name.Contains(flmName)).FirstOrDefault();
                        if (null == flmEntry)
                        {
                            return null;
                        }

                        var algoExtracter = new FlashAlgoExtracter();
                        using var flmStream = flmEntry.Open();

                        using MemoryStream memoryStream = new MemoryStream();
                        flmStream.CopyTo(memoryStream);
                        memoryStream.Seek(0, SeekOrigin.Begin);

                        flashAlgo = algoExtracter.Load(memoryStream);

                        // 修改flash的属性
                        var filteredFlashRegion = memoryMap.Regions.Where(x => x.MemoryType == MemoryType.FLASH).FirstOrDefault();
                        if (null == filteredFlashRegion)
                        {
                            return null;
                        }
                        var flashRegion = filteredFlashRegion as FlashRegion;
                        flashRegion.Algo = flashAlgo;
                        flashRegion.SectorSize = flashAlgo.SectorSize;
                        flashRegion.PageSize = flashAlgo.PageSize;

                        return new CommonTarget(targetName, memoryMap, flashAlgo);
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// 从pack文件中提取所有target名称
        /// </summary>
        /// <param name="packPath">pack文件路径</param>
        /// <returns>target名称列表</returns>
        public List<string> ExtractTargetNames(string packPath)
        {
            var targetNames = new List<string>();

            // 首先解压索引文件并解析
            using var archive = ZipFile.OpenRead(packPath);

            foreach (var entry in archive.Entries)
            {
                if (entry.Name.Contains(".pdsc"))
                {
                    // 解压缩
                    using var pdscStream = entry.Open();

                    var xdoc = XDocument.Load(pdscStream);
                    var devices = xdoc.Descendants("device").ToArray();

                    if (devices.Length > 0)
                    {
                        foreach (var device in devices)
                        {
                            // 如果Dname不为空，则添加到列表中
                            if (null != device.Attribute("Dname"))
                            {
                                targetNames.Add(device.Attribute("Dname")!.Value);
                            }
                        }
                    }
                }

            }

            return targetNames;
        }
    }
}
